#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <cstdio>


#include "QtApp.h"
#include "Game.h"
#include "Dealer.h"
#include "DealerPreFlop.h"
#include "DealerFlop.h"
#include "DealerTurn.h"
#include "DealerRiver.h"

#include "../Common/GameInfo.h"
#include "../Common/Poker.h"
#include "../Common/PokerTool.h"

class PokerTool;

using namespace std;

/* data singleton */		
Game * game;

// Montant de dépard des joueurs, se montant est sotcké en global tous au long des parties
int amountPlayer1 = PLAYER_AMOUNT;
int amountPlayer2 = PLAYER_AMOUNT;

string Game::getCountActiontoString()
{
	return PokerTool::intToString(countAction);
}

/*
 * Après avoir recu l'action réalisé par le joueur (trasmittion réseau, j'éxécute son action)
 */
void Game::actionPlayer(Player &player,QtApp *app)
{
	cout << "-----------------Start actionPlayer---------------------------" << endl;
	cout << "actionPlayer de (" <<  player.getName().toStdString() << ") = " << player.getAction().toStdString() << endl;

	//nombre de joueur ayant jouer sur le coup
	twoPlayerOnPlay++;
/*
	//Si on est su le river
	if(gameinfo.getGameState() == 3)
	{
		if(gameinfo.getPlayer(1).bet == gameinfo.getPlayer(2gameinfo.getPlayer(plus).bet && twoPlayerOnPlay >= 2)
		{
			cout << "--------twoPlayerOnPlay : "<< twoPlayerOnPlay <<"--------------etat 3----------" << endl;
			gameinfo.getPlayer(plusFaiblemain(gameinfo.getPlayers()[1],gameinfo.getPlayers()[2]) ).action = choice[0].c_str();
			attributPot();
			cout << "-------------Fin de partie--------------------" << endl;
			sr.endGame(app);
		}
	}
*/
	if(player.getAction().toStdString() == choice[0] || endGame == 1)
	{
		cout << "----------------------------------------------------"  <<endl;
		cout << "---------------------Action choix[0]----------------" << endl;
		//Si les deux joueurs on jouer
		if(twoPlayerOnPlay >= 2 )
		{
			gameinfo.setPot(gameinfo.getPot() + player.getMise());
			updateAllValuesPlayers();
			//attributPot();

			//Un joueur se couche donc fin de partie
			endGame = 1;

			//Nouveau joueur courant
			//gameinfo.setCurrentPlayer(1);

			//Nouvelle etat du jeu : pré-flop
			gameinfo.setGameState(0);

			// On reouvre la distribution après qu'un joueur se soit couché
			dealer->isDistribute = true;

			//fin de jeu si un joueur se couche
			app->endGame(gameinfo.getPlayer(1),gameinfo.getPlayer(2));
		}
		//Si seulement un joueur a jouer
		else
		{
			//modification de son choix en suit (call)
			player.setAction(1);
			updateAllValuesPlayers();
			//Nouveau joueur courant
			//gameinfo.setCurrentPlayer(2);
		}
	}
	else if(player.getAction().toStdString() == choice[1])
	{
		cout << "----------------------------------------------------"  <<endl;
		cout << "---------------------Action choix[1]----------------" << endl;
		gameinfo.setPot(gameinfo.getPot() + player.getMise());
		updateAllValuesPlayers();
		//incrémentation eta QtApp *dialogt du jeu, si les 2 joueurs on misé la même somme
		cout << "Le joueur suit : " << gameinfo.getPlayer(1).getBet() << "=="<< gameinfo.getPlayer(2).getBet()<< "-twoPlayerOnPlay:" <<twoPlayerOnPlay << endl;
	}
	else if(player.getAction().toStdString() == choice[2])
	{
		cout << "----------------------------------------------------"  <<endl;
		cout << "---------------------Action choix[2]----------------" << endl;
		gameinfo.setPot(gameinfo.getPot() + player.getMise() );
		updateAllValuesPlayers();
	}

	cout << "-----------------Finish actionPlayer---------------------------" << endl;
}
/*
 * A la fin d'une partie, il y a une affectation du pot au jour gagnant
 */
void Game::attributPot()
{
	cout << "---------------------Start attributPot---------------------------" << endl;
	cout << "partie->d.pot : " << gameinfo.getPot() << endl;
	cout << "player2.sommeTotal : " << gameinfo.getPlayer(2).getBankroll() << endl;
	cout << "player1.sommeTotal : " << gameinfo.getPlayer(1).getBankroll() << endl;

	if(gameinfo.getPlayer(1).getAction().toStdString() == choice[0])
	{
		gameinfo.getPlayer(2).setBankroll( gameinfo.getPlayer(2).getBankrollInt() + gameinfo.getPot() );
		gameinfo.getPlayer(2).setMise(0);
		gameinfo.getPlayer(1).setMise(0);
		gameinfo.getPlayer(2).setBet(0);
		gameinfo.getPlayer(1).setBet(0);
		amountPlayer1=gameinfo.getPlayer(1).getBankrollInt();
		amountPlayer2=gameinfo.getPlayer(2).getBankrollInt();
	}
	else if(gameinfo.getPlayer(2).getAction().toStdString() == choice[0])
	{
		gameinfo.getPlayer(1).setBankroll( gameinfo.getPlayer(1).getBankrollInt() + gameinfo.getPot() );
		gameinfo.getPlayer(1).setMise( 0 );
		gameinfo.getPlayer(2).setMise( 0 );
		gameinfo.getPlayer(2).setBet( 0 );
		gameinfo.getPlayer(1).setBet( 0 );
		amountPlayer1 = gameinfo.getPlayer(1).getBankrollInt();
		amountPlayer2 = gameinfo.getPlayer(2).getBankrollInt();
	}
	gameinfo.setPot(0);

	cout << "Le joueur 1 : " << gameinfo.getPlayer(1).getBankroll() << "-Le joueur 2 : " << gameinfo.getPlayer(2).getBankroll() << "-pot" << gameinfo.getPot() << endl;
	cout << "---------------------Finish attributPot---------------------------" << endl;
}
/**
 * Met a jour les valeurs, mise (sur un coup), mise en cours(depuis le debut de partie),
 * mise minimun(ce que doit mettre le joueur pour pouvoir poursuivre)
 */
void Game::updateAllValuesPlayers()
{
	// on rajoute à la mise en cours depuis le début de partie la mise du coup
	gameinfo.getPlayer(gameinfo.getCurrentPlayer()).setBet(gameinfo.getPlayer(gameinfo.getCurrentPlayer()).getBetInt() + gameinfo.getPlayer(gameinfo.getCurrentPlayer()).getMise() );

	//mise à jour mise minimun
	if(gameinfo.getCurrentPlayer() == 1)
	{
		gameinfo.getPlayer(2).setAmountToCall( gameinfo.getPlayer(1).getBetInt() - gameinfo.getPlayer(2).getBetInt() );
		gameinfo.getPlayer(1).setAmountToCall(0);
	}
	else
	{
		gameinfo.getPlayer(1).setAmountToCall(gameinfo.getPlayer(2).getBetInt() - gameinfo.getPlayer(1).getBetInt() );
		gameinfo.getPlayer(2).setAmountToCall(0);
	}

	// on retire la mise du coup a l'argent total dont il dispose
	gameinfo.getPlayer(gameinfo.getCurrentPlayer()).setBankroll( gameinfo.getPlayer(gameinfo.getCurrentPlayer()).getBankrollInt() - gameinfo.getPlayer(gameinfo.getCurrentPlayer()).getMise());

	// mise de l'argent des joueurs
	amountPlayer1=gameinfo.getPlayer(1).getBankrollInt();
	amountPlayer2=gameinfo.getPlayer(2).getBankrollInt();

	cout << "valeur joueurs :" << std::endl;
	cout << "         pot : " << gameinfo.getPot() << std::endl;
	cout << "         joueur 1 miseMinimun(amounToCall)   : " << gameinfo.getPlayer(1).getAmountToCall() 	<< endl;
	cout << "         joueur 1 miseEnCours(bet)           : " << gameinfo.getPlayer(1).getBet() 			<< endl;
	cout << "         joueur 1 mise(mise)                 : " << gameinfo.getPlayer(1).getMise() 			<< endl;
	cout << "         joueur 1 sommeTotal(bankroll)       : " << gameinfo.getPlayer(1).getBankroll()		<< endl;
	cout << "         joueur 2 miseMinimun(amounToCall)   : " << gameinfo.getPlayer(2).getAmountToCall() 	<< endl;
	cout << "         joueur 2 miseEnCours (bet)          : " << gameinfo.getPlayer(2).getBet()				<< endl;
	cout << "         joueur 2 mise(mise)                 : " << gameinfo.getPlayer(2).getMise()			<< endl;
	cout << "         jouedealerur 2 sommeTotal(bankroll) : " << gameinfo.getPlayer(2).getBankroll()		<< endl;
}

/*
 * Fonction a completer, determine la plus forte main entre 2 joueurs
 */
int Game::plusFaiblemain()
{
	cout << "plusFaiblemain" << endl;
	cout << gameinfo.getPlayer(1).toString(gameinfo.getPlayer(2).getBetInt(),gameinfo.getGameState(),0,0) << endl;
	cout << gameinfo.getPlayer(2).toString(gameinfo.getPlayer(1).getBetInt(),gameinfo.getGameState(),0,0) << endl;

	//fonction qui détermine le gagnant de manière aléatoire
	if(WINNER_BY_HAND_RANDOM)
	{
		gameinfo.getPlayer(1).setCombinationLabel("Random");
		gameinfo.getPlayer(2).setCombinationLabel("Random");
		return (rand()%2)+1;
	}
	//Si etat sur le turn ou un joueur a fait tapis
	if(gameinfo.getGameState() == 3 || ( gameinfo.getPlayer(1).getBankrollInt() <=0 || gameinfo.getPlayer(2).getBankrollInt() <=0 ) )
	{
		// Détermine le gagnant gace au compbinaisson
		Poker poker;
		gameinfo.winner = poker.getWinner(gameinfo);
		cout << "winner : " << gameinfo.winner << endl;
		cout << "getCombinationLabel(1): " << gameinfo.getPlayer(1).getCombinationLabel().toStdString() << endl;
		cout << "getCombinationLabel(2): " << gameinfo.getPlayer(2).getCombinationLabel().toStdString() << endl;
		return gameinfo.winner;
	}
	else
	{
		if( gameinfo.getPlayer(1).getAction().toStdString() == choice[0])
		{
			gameinfo.getPlayer(1).setCombinationLabel(choice[0].c_str());
			gameinfo.getPlayer(2).setCombinationLabel("Gagnant");
			return 2;
		}
		if( gameinfo.getPlayer(2).getAction().toStdString() == choice[0])
		{
			gameinfo.getPlayer(1).setCombinationLabel("Gagant");
			gameinfo.getPlayer(2).setCombinationLabel(choice[0].c_str());
			return 1;
		}
	}
	//Si bug alors retourne joueur 1 gagne par défaut
	cout << endl <<  endl << endl << "BUG WINNER"  << endl << endl << endl << endl;
	return 1;
}
/*
 * Envoi 2 messages, 1 au gagnant et 1 au perdant
 */
void Game::messageEndGame()
{
	cout << endl;
	cout << "---------------------------------------------------------" << endl;
	cout << "---------------------Start send messageEndGame-----------------" << endl;
	cout << gameinfo.getPlayer(1).getBet()<< endl;
	cout << "---------------------------------------------------------" << endl;
	cout << gameinfo.getPlayer(2).getBet() << endl;
	cout << "---------------------------------------------------------" << endl;
	// Pou l'apprentissage envoi réponse fin de partie
	// 1=joueur1, 2=joueur2
	//int winner = getwinner(gameinfo.getPlayers());
	plusFaiblemain();
	if(USE_COMMUNICATION_XML)
	{
		ie.sendMessageGame(gameinfo.toXml().toStdString(),gameinfo.getPlayer(1));
		ie.sendMessageGame(gameinfo.toXml().toStdString(),gameinfo.getPlayer(2));
	}
	else
	{
		if(gameinfo.winner==1)
		{

			ie.sendMessageGame(gameinfo.getPlayer(1).toString(
					gameinfo.getPlayer(2).getBetInt(),
					4,
					gameinfo.getPlayer(1).getBetInt(),
					1),gameinfo.getPlayer(1));
			ie.sendMessageGame(gameinfo.getPlayer(2).toString(
					gameinfo.getPlayer(2).getBetInt(),
					4,
					gameinfo.getPlayer(1).getBetInt(),
					0),gameinfo.getPlayer(2));
		}
		else
		{
			ie.sendMessageGame(gameinfo.getPlayer(1).toString(
					gameinfo.getPlayer(2).getBetInt(),
					4,
					gameinfo.getPlayer(1).getBetInt(),
					0),gameinfo.getPlayer(1));
			ie.sendMessageGame(gameinfo.getPlayer(2).toString(
					gameinfo.getPlayer(2).getBetInt(),
					4,
					gameinfo.getPlayer(1).getBetInt(),
					1),gameinfo.getPlayer(2));
		}
		/*
		if(gameinfo.winner==1)
		{
			ie.sendMessageGame("[partie[joueur[etat[5]][end[win]]]]",gameinfo.getPlayer(1));
			ie.sendMessageGame("[partie[joueur[etat[5]][end[lose]]]]",gameinfo.getPlayer(2));
		}
		else
		{
			ie.sendMessageGame("[partie[joueur[etat[5]][end[lose]]]]",gameinfo.getPlayer(1));
			ie.sendMessageGame("[partie[joueur[etat[5]][end[win]]]]",gameinfo.getPlayer(2));
		}
		*/
	}
	cout << "---------------------Finish send messageEndGame-----------------" << endl;
	cout << "----------------------------------------------------------------" << endl;

	//Inversion position des joueurs
	if( gameinfo.getPlayer(1).getPosition()==1 )
	{
		gameinfo.getPlayer(1).setPosition(2);
		gameinfo.getPlayer(1).setPosition(1);
	}
	else
	{
		gameinfo.getPlayer(1).setPosition(1);
		gameinfo.getPlayer(1).setPosition(2);
	}
}

void Game::conversionDealer()
{
	//pre-flop
		if(game->gameinfo.getGameState()==0 && game->dealer->isDelivering())
		{
			game->dealer = new DealerPreFlop(game->dealer);
		}
		//flop
		if(game->gameinfo.getGameState()==1 && game->dealer->isDelivering())
		{
			game->dealer = new DealerFlop(game->dealer);
		}
		//turn
		if(game->gameinfo.getGameState()==2 && game->dealer->isDelivering())
		{
			game->dealer = new DealerTurn(game->dealer);
		}
		//river
		if(game->gameinfo.getGameState()==3 && game->dealer->isDelivering())
		{
			game->dealer = new DealerRiver(game->dealer);
		}
}
Game * Game::getGame()
{
	if(game == NULL)
	{
		game = new Game();
		game->gameinfo.setPot(0);
		game->gameinfo.setCurrentPlayer(1);
		game->twoPlayerOnPlay=0;
		game->endGame=0;
		game->gameinfo.setGameState(0);
		game->countAction=0;
		game->dealer = new Dealer();
	}
	conversionDealer();
	return game;
}
Game * Game::getGame(string ipPlayer1,string ipPlayer2,string ipport1,string ipport2,string strategy1,string strategy2)
{
	cout << "------------------Start Game::getGame----------------------" << endl;
	// Si l'objet game non alloué
	if(game == NULL)
	{
		game = new Game();
		game->gameinfo.setPot(0);
		game->gameinfo.setCurrentPlayer(1);
		game->twoPlayerOnPlay=0;
		game->endGame=0;
		game->gameinfo.setGameState(0);
		game->numeroOfGame=1;
		game->countAction=0;
		game->dealer = new Dealer();
	}

	conversionDealer();

	// nouvelle distribution
	if( game->dealer->compteurDePartie == game->dealer->nbPartieAvantNouvelleDistribution ||  game->dealer->compteurDePartie == 0)
	{
		game->numeroOfGame = 1;
		//Initialisation du nombre de partie à réaliser de manière identique
		game->dealer->compteurDePartie = NBGAME;
		game->gameinfo.players.clear();
		game->cards.clear();

		game->cards =  game->dealer->initCards();
	}

	//pas de nouvelle distribution
	game->gameinfo.setPlayers(game->dealer->runGame(ipPlayer1, ipPlayer2,ipport1,ipport2,amountPlayer1,amountPlayer2,strategy1,strategy2));

	game->gameinfo.setPot(0);

	//distribution des blinds
	game->dealer->distriblind( game->gameinfo.getPlayer(1),game->gameinfo.getPlayer(2) );

	cout << "------------------Finish Game::getGame----------------------" << endl;

	return game;
}

